# -*- coding:utf-8 -*-
#!/usr/bin/python

from splinter import Browser
import re 
import sys
import sqlite3
import urlparse
"""
    @attention: default charset is utf-8
"""
class SessionManageTest(object):
    
    def __init__(self,browser,database,host,is_login=False,login_url=None,form_data=None):
        self.browser=browser
        self.database=database
        self.host=host
        self.is_login=is_login
        self.login_success=False
        self.login_url=login_url
        self.form_data=form_data
        self.rem="-----"
        if self.is_login:
            if not self.login_url :
                sys.exit("login url is not assigned")
            if not self.form_data:
                sys.exit("login form data is not assigned")
    
    def output(self,info):
        print self.rem+info
        
    """
        Function:Login
        @param login_url: the url you submit your form_data to
        @param form_data: the data you want to submit 
        @author: shenyuan
        @note: it doesn't support verify code and it only supports UTF-8 website
    """
    def Login(self):
        if self.is_login:
#             for (key,value) in self.form_data.items():
#                 if not isinstance(value,str) and not isinstance(value,unicode):
#                     self.form_data[key]=value.decode("utf-8")
            #browser=Browser("phantomjs")
            try:
                self.browser.visit(self.login_url)
                self.browser.fill_form(self.form_data)
                keyword="登录".decode("utf-8")
                login_xpath_lists=["//input[@value='%s']" % keyword,"//button[contains(.,'%s')]" % keyword]
                for login_xpath in login_xpath_lists:
                    if self.browser.find_by_xpath(login_xpath):
                        self.browser.find_by_xpath(login_xpath).first.click()
                        if self.browser.is_element_not_present_by_xpath(login_xpath,5):
                            return True
                        else:
                            self.output("state:Login failed")
                            return False
                self.output("state:Can't find the login entrance")
            except:
                self.output("state:Can't find the login entrance")
        
        return False
    
    """
            Function:check_cookie_attribute
    """
    def check_cookie_attribute(self):
        if self.is_login:
            if self.Login():
                self.output("state:Login Successfully")
                self.login_success=True
        """ 
        check cookie attributes
         """
        attributes_list={'httponly':"is likely accessed by a client side",'domain':False,'path':False,'expires':False}
        if self.login_success:
            attributes_list['secure']="not on encrypted channel"
            for cookie in self.browser.cookies.all():
                if cookie['secure']:
                    attributes_list['secure']=False
                    break
        #HTTPOnly attribute
        for cookie in self.browser.cookies.all():
            if cookie['httponly']:
                attributes_list['httponly']=False
                break
        #domain attribute
        for cookie in self.browser.cookies.all():
            if cookie['domain'].find(self.host)==-1:
                attributes_list['domain']="too loose"
                break
        #path attribute
        for cookie in self.browser.cookies.all():
            if not cookie['path'].endswith("/"):
                attributes_list['path']="too loose"
                break
        #expires attribute
        
        for (name,val) in attributes_list.items():
            if val:
                self.output("%s:%s" % (name,val))
                
    """
            Function:get_sessionid
            @param url: the url for the browser to visit
    """
    def get_sessionid(self,url):
        self.browser.visit(url)
        for cookie in self.browser.cookies.all():
            if re.match(r'.*sess(ion)?id',cookie['name'],re.I):
                session_id=cookie['value']
                return session_id
        return None
    
    """
            Function:check_session_fixation
            @param param: 
            @param param: 
            @note: it's based on login state
            @attention: get links from database
    """
    def check_session_fixation(self):
        if self.is_login and self.login_success:
            #links from database
            conn=sqlite3.connect(self.database)
            cur=conn.cursor()
            links=cur.execute("select path from stat limit 2").fetchall()
            conn.commit()
            conn.close()
            url_former=urlparse.urlunparse(('http',self.host,links[0][0],'','',''))
            url_latter=urlparse.urlunparse(('http',self.host,links[1][0],'','',''))
            former_sessionid=self.get_sessionid(url_former)
            latter_sessionid=self.get_sessionid(url_latter)
            if former_sessionid and former_sessionid==latter_sessionid:
                self.output("Sessionid:fixation problem")
        else:
            self.output("No in login state")
    
    def check(self):
        print "[--SessionManageTest--]"
        self.check_cookie_attribute()
        if self.login_success:
            self.check_session_fixation()
